#!/usr/bin/python

#
# Copyright 2008 Amit Shrestha
#

'''
This file is part of Words.

Words is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Words is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
'''

import sys
import re

from Word import Word

class DB:
    """stores word-database and implements utility functions
    """

    def __init__(self):
        self.words = []
        self.__patterns_to_index = {}
        self.__index_map = {}
        self.__number_of_words_mastered = 0
    
    def get_available_index_names(self):
        return self.__index_map.keys()
   
    def get_number_of_words_mastered(self):
        return self.__number_of_words_mastered

    def get_number_of_words_tested(self):
        count = 0
        for word in self.words:
            if int(word.stats['number_of_times_tested']) > 0: 
                count += 1
        return count

    def get_word(self,name):
        for word in self.words:
            if word.name == name:
                return word
        return None

    def mark_mastered(self,index):
        if(int(self.words[index].stats['mastered']) != 1):
            self.words[index].stats['mastered'] = str(1)
            self.__number_of_words_mastered += 1
            for k in self.__index_map.keys():
                try:
                    self.__index_map[k].remove(index)
                except: pass
    
    def reset_mastered_words(self):
        for word in self.words:
            word.stats['mastered'] = str(0)
        self.__number_of_words_mastered = 0

    def reset_number_of_times_tested(self):
        for word in self.words:
            word.stats['number_of_times_tested'] = str(0)

    def get_indices(self,index_name):
        """returns list of indices to words corresponding to given index_name
        """
        if self.__index_map.has_key(index_name):
            return self.__index_map[index_name]
        else: return []

    def read_db(self,db_path,patterns_to_index_path):
        self.db_path = db_path
        self.patterns_to_index_path = patterns_to_index_path

        self.__read_patterns_to_index(patterns_to_index_path)

        db = open(db_path,'r')
        ln = 0
        for line in db:
            ln += 1
            if not line.strip() or line.startswith('#'): continue
            
            splits = [x.strip() for x in line.split('::')]
            if len(splits) != 2:
                print "Error in line %d in file %s"%(ln,db_path)
                db.close()
                sys.exit(1)
            
            attr = splits[0].lower()
            value = splits[1]

            if attr == 'word':
                if(len(self.words) > 0):
                    last_word = self.words[-1]
                    if int(last_word.stats['mastered']) != 1:
                        for (k,v) in last_word.stats.iteritems():
                            self.__index_pattern("stats." + k,v,len(self.words)-1)
                        self.__index_pattern('word',last_word.name,len(self.words)-1)
                        for x in last_word.pronunciations:
                            self.__index_pattern('pronunciation',x,len(self.words)-1)
                        for x in last_word.synonyms:
                            self.__index_pattern('synonym',x,len(self.words)-1)
                        for x in last_word.antonyms:
                            self.__index_pattern('antonym',x,len(self.words)-1)
                        for x in last_word.meanings:
                            self.__index_pattern('meaning',x[0],len(self.words)-1)
                            for y in x[1]:
                                self.__index_pattern('example',y,len(self.words)-1)
                        for x in last_word.categories:
                            self.__index_pattern('category',x,len(self.words)-1)
                        for (k,v) in last_word.stats.iteritems():
                            self.__index_pattern(k,v,len(self.words)-1)
                self.words.append(Word(value))
            elif attr == 'pronunciations':
                pronunciations = value.split('#')
                self.words[-1].pronunciations.extend(pronunciations)
            elif attr == 'synonyms':
                synonyms = value.split('#')
                self.words[-1].synonyms.extend(synonyms)
            elif attr == 'antonyms':
                antonyms = value.split('#')
                self.words[-1].antonyms.extend(antonyms)
            elif attr == 'meaning':
                self.words[-1].meanings.append((value,[]))
            elif attr == 'example':
                self.words[-1].meanings[-1][1].append(value)
            elif attr == 'categories':
                categories = value.split('#')
                self.words[-1].categories.extend(categories)
            elif attr.startswith('stats.'):
                if(attr == 'stats.mastered' and int(value) == 1):
                    self.__number_of_words_mastered += 1
                self.words[-1].stats[attr.split('stats.')[1]] = value
            else:
                print "Unknown attribute in line %d" % ln
                db.close()
                sys.exit(1)
        db.close()

    def write_db(self,dbpath,patterns_to_index_path):
        db = open(dbpath,'w')
        db.write("#Compiled from WordNet. \n#Please see http://wordnet.princeton.edu/wordnet/license/ for full license terms\n\n")
        for word in self.words:
            db.write("word::%s\n" % word.name)
            if word.pronunciations: db.write("pronunciations::%s\n" % ("#".join(word.pronunciations)))
            if word.synonyms: db.write("synonyms::%s\n" % ("#".join(word.synonyms)))
            if word.antonyms: db.write("antonyms::%s\n" % ("#".join(word.antonyms)))
            for x in word.meanings:
                meaning = x[0]
                examples = x[1]
                db.write("meaning::%s\n" % meaning)
                for example in examples:
                    db.write("example::%s\n" % example)
            if word.categories: db.write("categories::%s\n" % ("#".join(word.categories)))
            for key,value in word.stats.iteritems():
                db.write("stats.%s::%s\n" % (key,value))
            db.write("\n")
        db.close()
        
        fpatterns = open(self.patterns_to_index_path,'r')
        patterns = fpatterns.read()
        fpatterns.close()
        fpatterns = open(patterns_to_index_path,'w')
        fpatterns.write(patterns)
        fpatterns.close()
    
    def __index_pattern(self,attr,value,index):
        for index_name,grp in self.__patterns_to_index.iteritems():
            if grp[0] == attr and re.match(grp[1],value):
                self.__index_map[index_name].append(index)

    def __read_patterns_to_index(self,patterns_to_index_path):
        pfile = open(patterns_to_index_path,'r')
        ln = 0
        for line in pfile:
            ln += 1
            if not line.strip() or line.startswith('#'): continue
            splits = [x.strip() for x in line.split('::')]
            if len(splits) != 3:
                print "Error in line %d in file %s"%(ln,patterns_to_index_path)
                pfile.close()
                sys.exit(1)
            (index_name,key,pattern) = splits
            self.__patterns_to_index[index_name] = (key,pattern)
            self.__index_map[index_name] = []
        pfile.close()
